package com.gitee.feizns.quickstart.jackson;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.gitee.feizns.dynamic.Ex;
import com.gitee.feizns.dynamic.reflect.Constructors;
import com.jayway.jsonpath.JsonPath;
import lombok.SneakyThrows;

import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;

/**
 * dict 值
 * @author feizns
 * @since 2024/12/9
 */
public class Val {

    /**
     * NULL
     */
    public static final Val Null = new Val(null);

    /**
     * JSON 节点
     */
    private final JsonNode jsonNode;

    /**
     * 将java对象作为值，对于字符串仅作为文本节点
     * <pre>{@code
     *     //2024-02
     *     System.out.println(of((Object) "['2024-02']").get(0).asYearMonth());
     * }</pre>
     * @param value 值
     */
    private Val(Object value) {
        if ( value instanceof Optional )
            value = ((Optional< ? >) value).orElse(null);
        if ( value instanceof Val )
            this.jsonNode = ((Val) value).jsonNode().deepCopy();
        else
            this.jsonNode = JsonUtils.node(value);
    }

    /**
     * 将对象作为值
     * <pre>{@code
     *  //["2024-02"]
     *  System.out.println(of("['2024-02']").json());
     *  //null
     *  System.out.println(parse((Object) "['2024-02']").get(0).asYearMonth());
     *  //2024-02
     *  System.out.println(of((Object) "2024-02").asYearMonth());
     *  //null
     *  System.out.println(parse((Object) "'2024-02'").asYearMonth());
     * }</pre>
     * @param object 对象
     * @return {@link Val}
     */
    @JsonCreator
    public static Val of(Object object) {
        return object == null ? Null : new Val(object);
    }

    /**
     * 将json字符串转换为值
     * <pre>{@code
     *  //"['2024-02']"
     *  System.out.println(of((Object) "['2024-02']").json());
     *  //2024-02
     *  System.out.println(parse("['2024-02']").get(0).asYearMonth());
     *  //null
     *  System.out.println(of("2024-02").asYearMonth());
     *  //2024-02
     *  System.out.println(parse("'2024-02'").asYearMonth());
     * }</pre>
     * @param json 值
     * @return {@link Val}
     */
    @SneakyThrows
    public static Val parse(String json) {
        return json == null ? Null : of(Ex.tryCatch(() -> JsonUtils.getObjectMapper().readTree(json)).get());
    }

    /**
     * JSON 节点
     * @return {@link JsonNode}
     */
    public JsonNode node() {
        return jsonNode;
    }

    /**
     * 转义一遍变字符
     * <pre>{@code
     *     //"[1,2,3]"
     *     System.out.println(of((Object) "[1,2,3]").json());
     *     //"\"[1,2,3]\""
     *     System.out.println(of((Object) "[1,2,3]").escape().json());
     *     //[1,2,3]
     *     System.out.println(of((Object) "[1,2,3]").raw().json());
     * }</pre>
     * @return {@link String}
     */
    public Val escape() {
        return of(json());
    }

    /**
     * 去除转义变对象
     * <pre>{@code
     *     //"[1,2,3]"
     *     System.out.println(of((Object) "[1,2,3]").json());
     *     //"\"[1,2,3]\""
     *     System.out.println(of((Object) "[1,2,3]").escape().json());
     *     //[1,2,3]
     *     System.out.println(of((Object) "[1,2,3]").raw().json());
     * }</pre>
     * @return {@link String}
     */
    public Val raw() {
        return parse(textValue());
    }

    /**
     * 将当前值作为json字符串转换为值
     * @see #raw()
     * @return {@link Val}
     */
    public Val parse() {
        return raw();
    }

    /**
     * 是否是null
     * @return boolean
     */
    public boolean isNull() {
        return jsonNode.isNull();
    }

    /**
     * 是否是空
     * @return boolean
     */
    public boolean isEmpty() {
        return jsonNode.isEmpty();
    }

    /**
     * 是否是文本
     * @return boolean
     */
    public boolean isTextual() {
        return jsonNode.isTextual();
    }

    /**
     * 是否是空文本
     * @return boolean
     */
    public boolean isEmptyTextual() {
        return isTextual() && jsonNode.textValue().isEmpty();
    }

    /**
     * 是否是数组
     * @return boolean
     */
    public boolean isArray() {
        return jsonNode.isArray();
    }

    /**
     * 是否是对象
     * @return boolean
     */
    public boolean isObject() {
        return jsonNode.isObject();
    }

    /**
     * 是否是json
     * @return boolean
     */
    public boolean isJson() {
        return !jsonNode.isMissingNode();
    }

    /**
     * JSON 格式
     * @return {@link JsonNode}
     */
    @JsonValue
    public JsonNode jsonNode() {
        return jsonNode;
    }

    /**
     * JSON 格式
     * @return {@link String}
     */
    public String json() {
        return jsonNode.toString();
    }

    /**
     * 格式化Json
     * @return {@link String}
     */
    public String pretty(){
        return jsonNode.toPrettyString();
    }

    /**
     * 作为 byte
     * @return byte
     */
    public byte byteValue() {
        return byteValue((byte) 0);
    }

    /**
     * 作为 byte
     * @param defaultValue 默认值
     * @return byte
     */
    public byte byteValue(byte defaultValue) {
        return as(Byte.class).orElse(defaultValue);
    }

    /**
     * 作为 short
     * @return short
     */
    public short shortValue() {
        return shortValue((short) 0);
    }

    /**
     * 作为 short
     * @param defaultValue 默认值
     * @return short
     */
    public short shortValue(short defaultValue) {
        return as(Short.class).orElse(defaultValue);
    }

    /**
     * 作为 int
     * @return int
     */
    public int intValue() {
        return jsonNode.asInt();
    }

    /**
     * 作为 int
     * @return int
     */
    public int intValue(int defaultValue) {
        return jsonNode.asInt(defaultValue);
    }

    /**
     * 作为 long
     * @return long
     */
    public long longValue() {
        return jsonNode.asLong();
    }

    /**
     * 作为 long
     * @return long
     */
    public long longValue(long defaultValue) {
        return jsonNode.asLong(defaultValue);
    }

    /**
     * 作为 float
     * @return float
     */
    public float floatValue() {
        return floatValue(0);
    }

    /**
     * 作为 float
     * @param defaultValue 默认值
     * @return float
     */
    public float floatValue(float defaultValue) {
        return as(Float.class).orElse(defaultValue);
    }

    /**
     * 作为 double
     * @return double
     */
    public double doubleValue() {
        return doubleValue(0);
    }

    /**
     * 作为 double
     * @param defaultValue 默认值
     * @return double
     */
    public double doubleValue(double defaultValue) {
        return jsonNode.asDouble(defaultValue);
    }

    /**
     * 作为布尔值
     * @return boolean
     */
    public boolean booleanValue() {
        return booleanValue(false);
    }

    /**
     * 作为布尔值
     * @param defaultValue 默认值
     * @return boolean
     */
    public boolean booleanValue(boolean defaultValue) {
        return jsonNode.asBoolean(defaultValue);
    }

    /**
     * 作为 {@link Number}
     * @return {@link Number}
     */
    public Number numberValue() {
        return jsonNode.numberValue();
    }

    /**
     * 作为 Big decimal
     * @return {@link BigDecimal}
     */
    public BigDecimal decimalValue() {
        return jsonNode.decimalValue();
    }

    /**
     * 作为字符串
     * @return {@link String}
     */
    public String textValue() {
        return asText().orElse(null);
    }

    /**
     * string 值
     * @return {@link String }
     */
    public String stringValue() {
        return as(String.class).orElse(null);
    }

    /**
     * string 值
     * @param value 价值
     * @return {@link String }
     */
    public String stringValue(String value) {
        return as(String.class).orElse(value);
    }

    /**
     * 列表值
     * {@link List}
     * @return {@link List}<{@link Object}>
     */
    public List<Object> listValue() {
        //noinspection unchecked
        return as(List.class).orElse(new ArrayList<>());
    }

    /**
     * {@link List}
     * @param elementType 类型
     * @return {@link List}<{@link T}>
     */
    public <T> List<T> listValue(Class<T> elementType) {
        return asList(elementType).orElse(new ArrayList<>());
    }

    /**
     * {@link Set}
     * {@link Set}
     * @return {@link Set}<{@link Object}>
     */
    public Set<Object> setValue() {
        //noinspection unchecked
        return as(Set.class).orElse(new LinkedHashSet<>());
    }

    /**
     * {@link Set}
     * @param elementType 类型
     * @return {@link Set}<{@link T}>
     */
    public <T> Set<T> setValue(Class<T> elementType) {
        return asSet(elementType).orElse(new LinkedHashSet<>());
    }

    /**
     * {@link Map}
     * @return {@link Map}<{@link String}, {@link Object}>
     */
    public Map<String, Object> mapValue() {
        return asMap(String.class, Object.class).orElse(new LinkedHashMap<>());
    }

    /**
     * {@link Map}
     * @param keyClass 类型
     * @param valueClass 值类
     * @return {@link Map}<{@link K}, {@link V}>
     */
    public <K, V> Map<K, V> mapValue(Class<K> keyClass, Class<V> valueClass) {
        return asMap(keyClass, valueClass).orElse(new LinkedHashMap<>());
    }

    /**
     * 作为 Big decimal
     * @return {@link Optional}<{@link BigDecimal}>
     */
    public Optional<BigDecimal> asBigDecimal() {
        return as(BigDecimal.class);
    }

    /**
     * 作为字符串
     * @return {@link Optional}<{@link String}>
     */
    public Optional<String> asText() {
        return Optional.ofNullable((jsonNode.isMissingNode() || jsonNode.isNull()) ? null : jsonNode.asText());
    }

    /**
     * 转换为数字
     * @return {@link Optional}<{@link Number}>
     */
    public Optional<Number> asNumber() {
        return Optional.ofNullable(jsonNode.numberValue());
    }

    /**
     * 作为列表
     * @param elementType 元素类型
     * @return {@link List}<{@link T}>
     */
    public <T> Optional<List<T>> asList(Class<T> elementType) {
        return as(JsonUtils.typeFactory().constructCollectionType(List.class, elementType));
    }

    /**
     * 作为集合
     * @return {@link Set}<{@link T}>
     */
    public <T> Optional<Set<T>> asSet(Class<T> elementType) {
        return as(JsonUtils.typeFactory().constructCollectionType(Set.class, elementType));
    }

    /**
     * 作为Map
     * @return {@link Optional}<{@link Map}<{@link String}, {@link Object}>>
     */
    public Optional<Map<String, Object>> asMap() {
        return asMap(String.class,Object.class);
    }

    /**
     * 作为Map
     * @param keyClass Key 类
     * @param valueClass 值类
     * @return {@link Optional}<{@link Map}<{@link K}, {@link V}>>
     */
    public <K, V> Optional<Map<K, V>> asMap(Class<K> keyClass, Class<V> valueClass) {
        return as(JsonUtils.typeFactory().constructMapType(Map.class, keyClass, valueClass));
    }

    /**
     * as 数组
     * @param elementType 元素类型
     * @return {@link T[] }
     */
    @SuppressWarnings("unchecked")
    public <T> T[] asArray(Class<T> elementType) {
        return (T[]) as(JsonUtils.typeFactory().constructArrayType(elementType)).orElse(Array.newInstance(elementType, 0));
    }

    /**
     * 作为 Stream
     * @param elementType 元素类型
     * @return {@link Stream}<{@link T}>
     */
    public <T> Stream<T> asStream(Class<T> elementType) {
        return asList(elementType).orElse(Collections.emptyList()).stream();
    }

    /**
     * 获取
     * @param key 钥匙
     * @return {@link Val}
     */
    public Val get(String key) {
        return of(jsonNode.path(key));
    }

    /**
     * 获取值
     * @param index 索引
     * @return {@link Val}
     */
    public Val get(int index) {
        return of(jsonNode.path(index));
    }

    /**
     * 值
     * @return {@link Optional}<{@link Object}>
     */
    public Object objectValue() {
        return as(Object.class).orElse(null);
    }

    /**
     * 值
     * @param defaultValue 默认值
     * @return {@link Object}
     */
    public Object objectValue(Object defaultValue) {
        return as(Object.class).orElse(defaultValue);
    }

    /**
     * 或默认新建实例
     * @param type 类型
     * @return {@link T}
     */
    public <T> T orDefaultNewInstance(Class<T> type) {
        return as(type).orElse(Constructors.newInstance(type));
    }


    /**
     * 或默认新建实例
     * @param type 类型
     * @return {@link T}
     */
    public <T> T asBean(Class<T> type) {
        return orDefaultNewInstance(type);
    }

    /**
     * 转换为指定类型
     * @param type 类型
     * @return {@link T}
     */
    public <T> Optional<T> as(Class<T> type) {
        String json = json();
        T val = JsonUtils.parse(json, type);
        return Optional.ofNullable(val);
    }

    /**
     * 转换为指定类型
     * @param type 类型
     * @return {@link T}
     */
    public <T> Optional<T> as(JavaType type) {
        T val = JsonUtils.parse(json(), type);
        return Optional.ofNullable(val);
    }

    /**
     * 转换为指定类型
     * @param type 类型
     * @return {@link T}
     */
    public <T> Optional<T> as(TypeReference<T> type) {
        T val = JsonUtils.parse(json(), type);
        return Optional.ofNullable(val);
    }

    /**
     * 通过jsonpath查找数据
     * @param jsonpath json路径
     * @return {@link Val}
     */
    public Val find(JsonPath jsonpath) {
        return Val.of(JsonPath.using(JPath.config).parse(json()).read(jsonpath));
    }

    /**
     * to 字符串
     * @return {@link String }
     */
    @Override
    public String toString() {
        return "Val(" + jsonNode + ")";
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Val val = (Val) o;
        return Objects.equals(jsonNode, val.jsonNode);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(jsonNode);
    }

}
